package com.m4f.web.controller;

import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.cache.CacheException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.m4f.business.model.Company;
import com.m4f.business.model.AdditionalInformation;
import com.m4f.utils.StackTraceUtil;
import com.m4f.business.service.AppConfigurationService;
import com.m4f.business.service.TagsCloudService;
import com.m4f.business.service.CompanyService;
import com.m4f.business.service.SearchService;
import com.m4f.business.service.helper.FormUploadInfo;

@Controller
@RequestMapping(value="/company")
public class CompanyController extends BaseController {
	

	private static final Logger LOGGER = Logger.getLogger(CompanyController.class.getName());
	
	@Autowired
	private CompanyService companyService;
	@Autowired
	private SearchService searchService;
	@Autowired
	private TagsCloudService cloudService;
	@Autowired
	private AppConfigurationService appConfigurationService;
	
	public CompanyController() throws CacheException {
		super();
		// TODO Auto-generated constructor stub
	}
	
	@RequestMapping(method=RequestMethod.GET)
	public String getCreateForm(Principal currentUser, Model model) {
		Company company = this.companyService.
			getCompanyByParticipant(currentUser.getName());
		if(company == null) {
			String message = this.getMessage("user.not.have.company",
					currentUser.getName());
			model.addAttribute("message", message);
			return "common/error";
		}
		model.addAttribute("company", company);
		model.addAttribute("additionalInformation", company.getAdditionalInformation());
		model.addAttribute("types", this.appConfigurationService.
				getGlobalConfiguration().getBestPracticeTypes());
		model.addAttribute("sicCodes", this.appConfigurationService.
				getGlobalConfiguration().getSICCodeTypes());
		try {
			FormUploadInfo uploadInfo = this.companyService.getVideoUploadData(company);
			model.addAttribute("uploadInfo", uploadInfo);
		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			String message = this.getMessage("company.data.create.form.error", 
					company.getCompanyInfo().getName());
			model.addAttribute("message", message);
			return "common/error";
		}
		return "company/dataManage";
	}
	
	@RequestMapping(value="/refresh-video", method=RequestMethod.GET)
	public String refreshVideo(Principal currentUser, Model model) {
		Company company = this.companyService.
			getCompanyByParticipant(currentUser.getName());
		if(company == null) {
			String message = this.getMessage("user.not.have.company",
					currentUser.getName());
			model.addAttribute("message", message);
			return "common/error";
		}
		try {
			this.companyService.refreshCompanyVideoInformation(company);
		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			String message = this.getMessage("video.refresh.errorx", 
					company.getCompanyInfo().getName());
			model.addAttribute("message", message);
			return "common/error";
		}
		return "redirect:/company";
	}
	
	@RequestMapping(value="/add-video/{companyId}", method=RequestMethod.GET)
	public String addVideo(@PathVariable Long companyId, 
			@RequestParam Integer status, 
			@RequestParam(required=false, defaultValue="") String id,
			@RequestParam(required=false, defaultValue="") String error,
			Model model) {
		Company company = this.companyService.getCompanyById(companyId);
		if(company == null) {
			String message = this.getMessage("company.not.exist", 
					companyId);
			model.addAttribute("message", message);
			return "common/error";
		}
		try {
			if(status == 200) {
				this.companyService.addVideoToCompany(company, id);
				this.companyService.updateVideoInformation(company);
			} else {
				/**
				 * Parsing error from external video service.
				 */
				String message = this.companyService.getVideoUploadErrorMessage(company, status);
				if(error!=null && !"".equals(error)) {
					message += " External error: " + error;
				}
				LOGGER.severe(message);
				model.addAttribute("message", message);
				return "common/error";
			}
		} catch(Exception e) {
			LOGGER.severe("Stack trace: " + StackTraceUtil.getStackTrace(e));
			String message = this.getMessage("video.upload.error.internal", 
					company.getCompanyInfo().getName());
			model.addAttribute("message", message);
			return "common/error";
		}
		return "redirect:/company";
	}
	
	
	@RequestMapping(method=RequestMethod.POST)
	public String save(@Valid Company company, 
			BindingResult result, Model model) {
		if (result.hasErrors()) {
			return "company/dataManage";
		}
		this.companyService.saveCompany(company);
		company = this.companyService.getCompanyById(company.getId());
		this.cloudService.clearTagsCloud();
		try {
			this.companyService.updateVideoInformation(company);
		} catch(Exception e) {
			LOGGER.severe("Stack trace: " + StackTraceUtil.getStackTrace(e));
			String message = this.getMessage("company.saving.error", 
					company.getCompanyInfo().getName());
			model.addAttribute("message", message);
			return "common/error";
		}
		return "redirect:/company";
	}
	
	
	@RequestMapping(value="/add-information", method=RequestMethod.POST)
	public String addInformation(Principal currentUser, 
			@Valid AdditionalInformation additionalInformation, 
			BindingResult result, Model model) {
		Company company = this.companyService.
		getCompanyByParticipant(currentUser.getName());
		if(company == null) {
			String message = this.getMessage("user.not.have.company",
					currentUser.getName());
			model.addAttribute("message", message);
			return "common/error";
		}
		this.companyService.addAdditionalInformation(company, additionalInformation);
		cloudService.clearTagsCloud();
		return "redirect:/company";
	}
	
	@RequestMapping(value="/detail/{companyId}", method=RequestMethod.GET)
	public String getView(Principal currentUser, @PathVariable Long companyId, 
			Model model) throws Exception {
		Company company = this.companyService.getCompanyById(companyId);
		if(company == null) {
			String message = this.getMessage("company.not.exist", 
					companyId);
			model.addAttribute("message", message);
			return "common/error";
		}
		model.addAttribute("company", company);
		model.addAttribute("sicCodes", this.appConfigurationService.
				getGlobalConfiguration().getSICCodeTypes());
		model.addAttribute("types", this.appConfigurationService.
				getGlobalConfiguration().getBestPracticeTypes());
		return "company/detail";
	}
	
	
	@RequestMapping(value="/video-delete/{companyId}", method=RequestMethod.GET)
	public String removeVideo(@PathVariable Long companyId, Model model) {
		Company company =  this.companyService.getCompanyById(companyId);
		if(company == null) {
			String message = this.getMessage("company.not.exist", 
					companyId);
			model.addAttribute("message", message);
			return "common/error";
		}
		try {
			this.companyService.deleteVideoFromCompany(company);
		} catch(Exception e) {
			LOGGER.severe(StackTraceUtil.getStackTrace(e));
			String message = this.getMessage("video.remove.error", 
					company.getCompanyInfo().getName()); 
			model.addAttribute("message", message);
			return "common/error";
		} 
		return "redirect:/company";
	}
	
	@RequestMapping(value="/directory/complete", method=RequestMethod.GET)
	public String getCompleteDirectory(Model model) {
		List<Company> companies = this.companyService.getAllCompanies();
		model.addAttribute("companies", companies);
		return "company/directory";
	}
	
	
	@RequestMapping(value="/facet/activity-sector/{tag}", method=RequestMethod.GET)
	public String searchByActivitySector(@PathVariable String tag, Model model) 
			throws IOException, ClassNotFoundException {
		String order = "asc";
		boolean orderAsc = true;
		if("desc".equals(order)) {
			orderAsc = false;
		}
		List<Company> companies = this.searchService.
			searchCompaniesByActivitySector(true, orderAsc, tag);
		model.addAttribute("companies", companies);
		model.addAttribute("order", order);
		model.addAttribute("cloud", cloudService.getTagsCloud());
		model.addAttribute("bestPracticeTypes",
				this.appConfigurationService.
				getGlobalConfiguration().getBestPracticeTypes());
		model.addAttribute("tag", "sicCode." + tag);
		return "company/list";
	}
	
	@RequestMapping(value="/facet/innovation-type/{tag}", method=RequestMethod.GET)
	public String searchByInnovationType(@PathVariable String tag, Model model) 
			throws IOException, ClassNotFoundException {
		String order = "asc";
		boolean orderAsc = true;
		if("desc".equals(order)) {
			orderAsc = false;
		}
		List<Company> companies = this.searchService.
			searchCompaniesByInnovationType(true, orderAsc, tag);
		model.addAttribute("companies", companies);
		model.addAttribute("order", order);
		model.addAttribute("cloud", cloudService.getTagsCloud());
		model.addAttribute("bestPracticeTypes",
				this.appConfigurationService.
				getGlobalConfiguration().getBestPracticeTypes());
		model.addAttribute("tag", "innovationType." + tag);
		return "company/list";
	}
	
	@RequestMapping(value="/list", method=RequestMethod.GET)
	public String getList(Model model) 
		throws IOException, ClassNotFoundException {
		boolean orderAsc = true;
		List<Company> companies = this.searchService.searchCompanies(true, orderAsc);
		model.addAttribute("companies", companies);
		model.addAttribute("order", "asc");
		model.addAttribute("cloud", cloudService.getTagsCloud());
		model.addAttribute("bestPracticeTypes",
				this.appConfigurationService.
				getGlobalConfiguration().getBestPracticeTypes());
		return "company/list";
	}
	
	@RequestMapping(value="/directory", method=RequestMethod.GET)
	public String getDirectory(Model model) 
		throws IOException, ClassNotFoundException {
		boolean orderAsc = true;
		List<Company> companies = this.searchService.searchCompanies(true, orderAsc);
		model.addAttribute("companies", companies);
		model.addAttribute("order", "asc");
		model.addAttribute("cloud", cloudService.getTagsCloud());
		return "company/directory";
	}
	
	@RequestMapping(value="/search", method=RequestMethod.POST)
	public String searchByName(@RequestParam String pattern, 
				Model model) {
		boolean orderAsc = true;
		List<Company> companies = this.searchService.searchCompanies(true, orderAsc);
		model.addAttribute("companies", companies);
		model.addAttribute("order", "asc");
		return "company/directory";
	}
	
	@RequestMapping(value="/download-sheet", method=RequestMethod.GET)
	public void downloadProjectSheet(Principal currentUser, 
			HttpServletRequest request, HttpServletResponse response) 
				throws Exception {
		Company company = this.companyService.
			getCompanyByParticipant(currentUser.getName());
		if(company == null) {
			return;
		}
		StringBuffer contentDisposition = new StringBuffer("attachment; filename=\"");
	    contentDisposition.append(company.getCompanyInfo().getName() + "-project-sheet");
	    contentDisposition.append(".doc\"");
		response.setHeader("Content-Type", "application/msword");
	    response.setHeader("Content-Disposition", contentDisposition.toString());
		this.companyService.downloadProjectSummaryDocument(company, response.getOutputStream());
	}
	
	@RequestMapping(value="/download-summary/{companyId}", method=RequestMethod.GET)
	public void downloadProjectSummary(@PathVariable Long companyId, 
			HttpServletRequest request, HttpServletResponse response) 
				throws Exception {
		Company company =  this.companyService.getCompanyById(companyId);
		if(company == null) {
			return;
		}
		StringBuffer contentDisposition = new StringBuffer("attachment; filename=\"");
	    contentDisposition.append(company.getCompanyInfo().getName() + "-project-sheet");
	    contentDisposition.append(".pdf\"");
		response.setHeader("Content-Type", "application/pdf");
	    response.setHeader("Content-Disposition", contentDisposition.toString());
		this.companyService.downloadProjectSummaryPDF(company, response.getOutputStream());
	}
	
	@RequestMapping(value="/upload-sheet", method=RequestMethod.POST)
	public String uploadProjectSheet(Principal currentUser, 
			@RequestParam("file") MultipartFile file) 
				throws Exception {
		Company company = this.companyService.
			getCompanyByParticipant(currentUser.getName());
		if(company == null) {
			return "common/error";
		}
		List<String> supportedMimeTypes = new ArrayList<String>();
		supportedMimeTypes.add("application/msword");
		supportedMimeTypes.add("application/vnd.ms-word");
		if(!this.isSupportedMimeType(supportedMimeTypes, file.getContentType())){
			return "redirect:/error/file-format-error";
		}
		this.companyService.updateProjectSummaryDocument(company, file.getBytes());
		return "redirect:/company";
	}
	
	
	
}